namespace DotNetNuke.UI.Skins
{
    using DotNetNuke.Common;
    using DotNetNuke.Common.Utilities;
    using DotNetNuke.Entities.Modules;
    using DotNetNuke.Security;
    using DotNetNuke.Services.Localization;
    using Microsoft.VisualBasic;
    using Microsoft.VisualBasic.CompilerServices;
    using System;
    using System.Collections;
    using System.IO;
    using System.Runtime.CompilerServices;
    using System.Text.RegularExpressions;
    using System.Web;
    using System.Xml;

    /// -----------------------------------------------------------------------------
    /// Project	 : DotNetNuke
    /// Class	 : SkinFileProcessor
    /// 
    /// -----------------------------------------------------------------------------
    /// <summary>
    /// Handles processing of a list of uploaded skin files into a working skin.
    /// </summary>
    /// <remarks>
    /// </remarks>
    /// <history>
    /// [willhsc]	3/3/2004	Created
    /// </history>
    /// -----------------------------------------------------------------------------
    public class SkinFileProcessor
    {
        private string DUPLICATE_DETAIL;
        private string DUPLICATE_ERROR;
        private string FILE_BEGIN;
        private string FILE_END;
        private string FILES_END;
        private string INITIALIZE_PROCESSOR;
        private string LOAD_SKIN_TOKEN;
        private readonly ControlParser m_ControlFactory;
        private readonly Hashtable m_ControlList;
        private string m_Message;
        private readonly PathParser m_PathFactory;
        private readonly XmlDocument m_SkinAttributes;
        private readonly string m_SkinName;
        private readonly string m_SkinPath;
        private readonly string m_SkinRoot;
        private string PACKAGE_LOAD;
        private string PACKAGE_LOAD_ERROR;

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// SkinFileProcessor class constructor.
        /// </summary>
        /// <remarks>
        /// This constructor parses a memory based skin
        /// </remarks>
        /// <history>
        /// [cnurse]	3/21/2005	Created
        /// </history>
        /// -----------------------------------------------------------------------------
        public SkinFileProcessor(string ControlKey, string ControlSrc)
        {
            this.m_SkinAttributes = new XmlDocument();
            this.m_PathFactory = new PathParser();
            this.m_ControlList = new Hashtable();
            this.m_Message = "";
            this.INITIALIZE_PROCESSOR = DotNetNuke.Services.Localization.Localization.GetString("StartProcessor", DotNetNuke.Common.Globals.GetPortalSettings());
            this.PACKAGE_LOAD = DotNetNuke.Services.Localization.Localization.GetString("PackageLoad", DotNetNuke.Common.Globals.GetPortalSettings());
            this.PACKAGE_LOAD_ERROR = DotNetNuke.Services.Localization.Localization.GetString("PackageLoad.Error", DotNetNuke.Common.Globals.GetPortalSettings());
            this.DUPLICATE_ERROR = DotNetNuke.Services.Localization.Localization.GetString("DuplicateSkinObject.Error", DotNetNuke.Common.Globals.GetPortalSettings());
            this.DUPLICATE_DETAIL = DotNetNuke.Services.Localization.Localization.GetString("DuplicateSkinObject.Detail", DotNetNuke.Common.Globals.GetPortalSettings());
            this.LOAD_SKIN_TOKEN = DotNetNuke.Services.Localization.Localization.GetString("LoadingSkinToken", DotNetNuke.Common.Globals.GetPortalSettings());
            this.FILE_BEGIN = DotNetNuke.Services.Localization.Localization.GetString("BeginSkinFile", DotNetNuke.Common.Globals.GetPortalSettings());
            this.FILE_END = DotNetNuke.Services.Localization.Localization.GetString("EndSkinFile", DotNetNuke.Common.Globals.GetPortalSettings());
            this.FILES_END = DotNetNuke.Services.Localization.Localization.GetString("EndSkinFiles", DotNetNuke.Common.Globals.GetPortalSettings());
            this.m_ControlList.Add(ControlKey, ControlSrc);
            this.m_ControlFactory = new ControlParser(this.m_ControlList);
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// SkinFileProcessor class constructor.
        /// </summary>
        /// <param name="SkinPath">File path to the portals upload directory.</param>
        /// <param name="SkinRoot">Specifies type of skin (Skins or Containers)</param>
        /// <param name="SkinName">Name of folder in which skin will reside (Zip file name)</param>
        /// <remarks>
        /// The constructor primes the file processor with path information and
        /// control data that should only be retrieved once.  It checks for the
        /// existentce of a skin level attribute file and read it in, if found.
        /// It also sorts through the complete list of controls and creates
        /// a hashtable which contains only the skin objects and their source paths.
        /// These are recognized by their ControlKey's which are formatted like
        /// tokens ("[TOKEN]").  The hashtable is required for speed as it will be
        /// processed for each token found in the source file by the Control Parser.
        /// </remarks>
        /// <history>
        /// [willhsc]	3/3/2004	Created
        /// </history>
        /// -----------------------------------------------------------------------------
        public SkinFileProcessor(string SkinPath, string SkinRoot, string SkinName)
        {
            this.m_SkinAttributes = new XmlDocument();
            this.m_PathFactory = new PathParser();
            this.m_ControlList = new Hashtable();
            this.m_Message = "";
            this.INITIALIZE_PROCESSOR = DotNetNuke.Services.Localization.Localization.GetString("StartProcessor", DotNetNuke.Common.Globals.GetPortalSettings());
            this.PACKAGE_LOAD = DotNetNuke.Services.Localization.Localization.GetString("PackageLoad", DotNetNuke.Common.Globals.GetPortalSettings());
            this.PACKAGE_LOAD_ERROR = DotNetNuke.Services.Localization.Localization.GetString("PackageLoad.Error", DotNetNuke.Common.Globals.GetPortalSettings());
            this.DUPLICATE_ERROR = DotNetNuke.Services.Localization.Localization.GetString("DuplicateSkinObject.Error", DotNetNuke.Common.Globals.GetPortalSettings());
            this.DUPLICATE_DETAIL = DotNetNuke.Services.Localization.Localization.GetString("DuplicateSkinObject.Detail", DotNetNuke.Common.Globals.GetPortalSettings());
            this.LOAD_SKIN_TOKEN = DotNetNuke.Services.Localization.Localization.GetString("LoadingSkinToken", DotNetNuke.Common.Globals.GetPortalSettings());
            this.FILE_BEGIN = DotNetNuke.Services.Localization.Localization.GetString("BeginSkinFile", DotNetNuke.Common.Globals.GetPortalSettings());
            this.FILE_END = DotNetNuke.Services.Localization.Localization.GetString("EndSkinFile", DotNetNuke.Common.Globals.GetPortalSettings());
            this.FILES_END = DotNetNuke.Services.Localization.Localization.GetString("EndSkinFiles", DotNetNuke.Common.Globals.GetPortalSettings());
            this.Message = this.Message + SkinController.FormatMessage(this.INITIALIZE_PROCESSOR, SkinRoot + " :: " + SkinName, 0, false);
            this.m_SkinRoot = SkinRoot;
            this.m_SkinPath = SkinPath;
            this.m_SkinName = SkinName;
            string FileName = this.SkinPath + this.SkinRoot + @"\" + this.SkinName + @"\" + SkinRoot.Substring(0, SkinRoot.Length - 1) + ".xml";
            if (File.Exists(FileName))
            {
                try
                {
                    this.SkinAttributes.Load(FileName);
                    this.Message = this.Message + SkinController.FormatMessage(this.PACKAGE_LOAD, Path.GetFileName(FileName), 2, false);
                }
                catch (Exception exception1)
                {
                    
                    Exception ex = exception1;
                    this.Message = this.Message + SkinController.FormatMessage(string.Format(this.PACKAGE_LOAD_ERROR, ex.Message), Path.GetFileName(FileName), 2, true);
                    
                }
            }
            ArrayList arrModuleControls = new ModuleControlController().GetModuleControls(Null.NullInteger);
            int refIntHelperL0 = arrModuleControls.Count - 1;
            for (int i = 0; i <= refIntHelperL0; i++)
            {
                ModuleControlInfo objModuleControl = (ModuleControlInfo) arrModuleControls[i];
                if (objModuleControl.ControlType == SecurityAccessLevel.SkinObject)
                {
                    string Token = objModuleControl.ControlKey.ToUpper();
                    if (this.m_ControlList.ContainsKey(Token))
                    {
                        this.Message = this.Message + SkinController.FormatMessage(string.Format(this.DUPLICATE_ERROR, objModuleControl.ControlKey.ToString().ToUpper()), string.Format(this.DUPLICATE_DETAIL, (string) this.m_ControlList[Token], objModuleControl.ControlSrc.ToString()), 2, true);
                    }
                    else
                    {
                        this.Message = this.Message + SkinController.FormatMessage(string.Format(this.LOAD_SKIN_TOKEN, objModuleControl.ControlKey.ToString().ToUpper()), objModuleControl.ControlSrc.ToString(), 2, false);
                        this.m_ControlList.Add(Token, objModuleControl.ControlSrc);
                    }
                }
            }
            this.m_ControlFactory = new ControlParser(this.m_ControlList);
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// Perform processing on list of files to generate skin.
        /// </summary>
        /// <param name="FileList">ArrayList of files to be processed.</param>
        /// <returns>HTML formatted string of informational messages.</returns>
        /// <remarks>
        /// </remarks>
        /// <history>
        /// [willhsc]	3/3/2004	Created
        /// </history>
        /// -----------------------------------------------------------------------------
        public string ProcessList(ArrayList FileList)
        {
            return this.ProcessList(FileList, SkinParser.Localized);
        }

        public string ProcessList(ArrayList FileList, SkinParser ParseOption)
        {
            IEnumerator refObjectHelperL0=null;
            try
            {
                refObjectHelperL0 = FileList.GetEnumerator();
                while (refObjectHelperL0.MoveNext())
                {
                    string FileName = Conversions.ToString(refObjectHelperL0.Current);
                    this.Message = this.Message + SkinController.FormatMessage(this.FILE_BEGIN, Path.GetFileName(FileName), 0, false);
                    SkinFile objSkinFile = new SkinFile(this.SkinRoot, FileName, this.SkinAttributes);
                    string refStringHelperL0 = objSkinFile.FileExtension;
                    if ((((refStringHelperL0 == ".htm") || (refStringHelperL0 == ".html")) ? 1 : 0) != 0)
                    {
                        SkinFile refObjectHelperS1 = objSkinFile;
                        string refStringHelperS1 = refObjectHelperS1.Contents;
                        refObjectHelperS1.Contents = refStringHelperS1;
                        //this.Message = this.Message + this.PathFactory.Parse(ref refStringHelperS1, ref this.PathFactory.HTMLList, objSkinFile.SkinRootPath, ParseOption);
                        ArrayList htmlList = PathFactory.HTMLList;
                        this.Message = this.Message + this.PathFactory.Parse(ref refStringHelperS1, ref htmlList, objSkinFile.SkinRootPath, ParseOption);
                        refObjectHelperS1 = objSkinFile;
                        refStringHelperS1 = refObjectHelperS1.Contents;
                        refObjectHelperS1.Contents = refStringHelperS1;
                        this.Message = this.Message + this.ControlFactory.Parse(ref refStringHelperS1, objSkinFile.Attributes);
                        this.Message = this.Message + objSkinFile.PrependASCXDirectives(this.ControlFactory.Registrations);
                    }
                    objSkinFile.Write();
                    this.Message = this.Message + objSkinFile.Messages;
                    this.Message = this.Message + SkinController.FormatMessage(this.FILE_END, Path.GetFileName(FileName), 1, false);
                }
            }
            finally
            {
                if (refObjectHelperL0 is IDisposable)
                {
                    (refObjectHelperL0 as IDisposable).Dispose();
                }
            }
            this.Message = this.Message + SkinController.FormatMessage(this.FILES_END, this.SkinRoot + " :: " + this.SkinName, 0, false);
            return this.Message;
        }

        public string ProcessSkin(string SkinSource, XmlDocument SkinAttributes, SkinParser ParseOption)
        {
            SkinFile objSkinFile = new SkinFile(SkinSource, SkinAttributes);
            SkinFile refObjectHelperS0 = objSkinFile;
            string refStringHelperS0 = refObjectHelperS0.Contents;
            refObjectHelperS0.Contents = refStringHelperS0;
            this.Message = this.Message + this.ControlFactory.Parse(ref refStringHelperS0, objSkinFile.Attributes);
            this.Message = this.Message + objSkinFile.PrependASCXDirectives(this.ControlFactory.Registrations);
            return objSkinFile.Contents;
        }

        private ControlParser ControlFactory
        {
            get
            {
                return this.m_ControlFactory;
            }
        }

        private string Message
        {
            get
            {
                return this.m_Message;
            }
            set
            {
                this.m_Message = value;
            }
        }

        private PathParser PathFactory
        {
            get
            {
                return this.m_PathFactory;
            }
        }

        private XmlDocument SkinAttributes
        {
            get
            {
                return this.m_SkinAttributes;
            }
        }

        public string SkinName
        {
            get
            {
                return this.m_SkinName;
            }
        }

        public string SkinPath
        {
            get
            {
                return this.m_SkinPath;
            }
        }

        public string SkinRoot
        {
            get
            {
                return this.m_SkinRoot;
            }
        }

        /// -----------------------------------------------------------------------------
        /// Project	 : DotNetNuke
        /// Class	 : SkinFileProcessor.ControlParser
        /// 
        /// -----------------------------------------------------------------------------
        /// <summary>
        /// Parsing functionality for token replacement in new skin files.
        /// </summary>
        /// <remarks>
        /// This class encapsulates the data and methods necessary to appropriately
        /// handle all the token parsing needs for new skin files (which is appropriate
        /// only for HTML files).  The parser accomodates some ill formatting of tokens
        /// (ignoring whitespace and casing) and allows for naming of token instances
        /// if more than one instance of a particular control is desired on a skin.  The
        /// proper syntax for an instance is: "[TOKEN_INSTANCE]" where the instance can
        /// be any alphanumeric string.  Generated control ID's all take the
        /// form of "TOKENINSTANCE".
        /// </remarks>
        /// <history>
        /// [willhsc]	3/3/2004	Created
        /// </history>
        /// -----------------------------------------------------------------------------
        private class ControlParser
        {
            private XmlDocument m_Attributes = new XmlDocument();
            private readonly Hashtable m_ControlList = new Hashtable();
            private readonly string m_InitMessages = "";
            private string m_ParseMessages = "";
            private ArrayList m_RegisterList = new ArrayList();

            /// -----------------------------------------------------------------------------
            /// <summary>
            /// ControlParser class constructor.
            /// </summary>
            /// <remarks>
            /// The constructor processes accepts a hashtable of skin objects to process against.
            /// </remarks>
            /// <history>
            /// [willhsc]	3/3/2004	Created
            /// </history>
            /// -----------------------------------------------------------------------------
            public ControlParser(Hashtable ControlList)
            {
                this.m_ControlList = (Hashtable) ControlList.Clone();
            }

            /// -----------------------------------------------------------------------------
            /// <summary>
            /// Perform parsing on the specified source file using the specified attributes.
            /// </summary>
            /// <param name="Source">Pointer to Source string to be parsed.</param>
            /// <param name="Attributes">XML document containing token attribute information (can be empty).</param>
            /// <remarks>
            /// This procedure invokes a handler for each match of a formatted token.
            /// The attributes are first set because they will be referenced by the
            /// match handler.
            /// </remarks>
            /// <history>
            /// [willhsc]	3/3/2004	Created
            /// </history>
            /// -----------------------------------------------------------------------------
            public string Parse(ref string Source, XmlDocument Attributes)
            {
                this.Messages = this.m_InitMessages;
                this.Attributes = Attributes;
                this.RegisterList.Clear();
                Source = new Regex(@"\[\s*(?<token>\w*)\s*:?\s*(?<instance>\w*)\s*]", RegexOptions.IgnoreCase).Replace(Source, this.Handler);
                return this.Messages;
            }

            /// -----------------------------------------------------------------------------
            /// <summary>
            /// Process regular expression matches.
            /// </summary>
            /// <param name="m">Regular expression match for token which requires processing.</param>
            /// <returns>Properly formatted token.</returns>
            /// <remarks>
            /// The handler is invoked by the Regex.Replace method once for each match that
            /// it encounters.  The returned value of the handler is substituted for the
            /// original match.  So the handler properly formats the replacement for the
            /// token and returns it instead.  If an unknown token is encountered, the token
            /// is unmodified.  This can happen if a token is used for a skin object which
            /// has not yet been installed.
            /// </remarks>
            /// <history>
            /// [willhsc]	3/3/2004	Created
            /// </history>
            /// -----------------------------------------------------------------------------
            private string TokenMatchHandler(Match m)
            {
                string TOKEN_PROC = DotNetNuke.Services.Localization.Localization.GetString("ProcessToken", DotNetNuke.Common.Globals.GetPortalSettings());
                string TOKEN_SKIN = DotNetNuke.Services.Localization.Localization.GetString("SkinToken", DotNetNuke.Common.Globals.GetPortalSettings());
                string TOKEN_PANE = DotNetNuke.Services.Localization.Localization.GetString("PaneToken", DotNetNuke.Common.Globals.GetPortalSettings());
                string TOKEN_FOUND = DotNetNuke.Services.Localization.Localization.GetString("TokenFound", DotNetNuke.Common.Globals.GetPortalSettings());
                string TOKEN_FORMAT = DotNetNuke.Services.Localization.Localization.GetString("TokenFormat", DotNetNuke.Common.Globals.GetPortalSettings());
                string TOKEN_NOTFOUND_INFILE = DotNetNuke.Services.Localization.Localization.GetString("TokenNotFoundInFile", DotNetNuke.Common.Globals.GetPortalSettings());
                string CONTROL_FORMAT = DotNetNuke.Services.Localization.Localization.GetString("ControlFormat", DotNetNuke.Common.Globals.GetPortalSettings());
                string TOKEN_NOTFOUND = DotNetNuke.Services.Localization.Localization.GetString("TokenNotFound", DotNetNuke.Common.Globals.GetPortalSettings());
                string Token = m.Groups["token"].Value.ToUpper();
                string ControlName = Token + m.Groups["instance"].Value;
                string AttributeNode = Token + Convert.ToString(RuntimeHelpers.GetObjectValue(Interaction.IIf(m.Groups["instance"].Value == "", "", ":" + m.Groups["instance"].Value)));
                this.Messages = this.Messages + SkinController.FormatMessage(TOKEN_PROC, "[" + AttributeNode + "]", 2, false);
                if (this.ControlList.ContainsKey(Token) | (Token.IndexOf("CONTENTPANE") != -1))
                {
                    string SkinControl = "";
                    if (this.ControlList.ContainsKey(Token))
                    {
                        this.Messages = this.Messages + SkinController.FormatMessage(TOKEN_SKIN, (string) this.ControlList[Token], 2, false);
                    }
                    else
                    {
                        this.Messages = this.Messages + SkinController.FormatMessage(TOKEN_PANE, Token, 2, false);
                    }
                    if (this.Attributes.DocumentElement != null)
                    {
                        XmlNode xmlSkinAttributeRoot = this.Attributes.DocumentElement.SelectSingleNode("descendant::Object[Token='[" + AttributeNode + "]']");
                        if (xmlSkinAttributeRoot != null)
                        {
                            IEnumerator refObjectHelperL0=null;
                            this.Messages = this.Messages + SkinController.FormatMessage(TOKEN_FOUND, "[" + AttributeNode + "]", 2, false);
                            try
                            {
                                refObjectHelperL0 = xmlSkinAttributeRoot.SelectNodes(".//Settings/Setting").GetEnumerator();
                                while (refObjectHelperL0.MoveNext())
                                {
                                    XmlNode xmlSkinAttribute = (XmlNode) refObjectHelperL0.Current;
                                    if (xmlSkinAttribute.SelectSingleNode("Value").InnerText != "")
                                    {
                                        this.Messages = this.Messages + SkinController.FormatMessage(TOKEN_FORMAT, xmlSkinAttribute.SelectSingleNode("Name").InnerText + "=\"" + xmlSkinAttribute.SelectSingleNode("Value").InnerText + "\"", 2, false);
                                        SkinControl = SkinControl + " " + xmlSkinAttribute.SelectSingleNode("Name").InnerText + "=\"" + xmlSkinAttribute.SelectSingleNode("Value").InnerText.Replace("\"", "&quot;") + "\"";
                                    }
                                }
                            }
                            finally
                            {
                                if (refObjectHelperL0 is IDisposable)
                                {
                                    (refObjectHelperL0 as IDisposable).Dispose();
                                }
                            }
                        }
                        else
                        {
                            this.Messages = this.Messages + SkinController.FormatMessage(TOKEN_NOTFOUND_INFILE, "[" + AttributeNode + "]", 2, false);
                        }
                    }
                    if (this.ControlList.ContainsKey(Token))
                    {
                        SkinControl = "dnn:" + ControlName + " runat=\"server\" id=\"dnn" + ControlName + "\"" + SkinControl;
                        this.RegisterList.Add("<%@ Register TagPrefix=\"dnn\" TagName=\"" + ControlName + "\" Src=\"~/" + ((string) this.ControlList[Token]) + "\" %>\r\n");
                        this.Messages = this.Messages + SkinController.FormatMessage(CONTROL_FORMAT, "&lt;" + SkinControl + " /&gt;", 2, false);
                        return ("<" + SkinControl + " />");
                    }
                    if (SkinControl.ToLower().IndexOf("id=") == -1)
                    {
                        SkinControl = " id=\"ContentPane\"";
                    }
                    SkinControl = "div runat=\"server\"" + SkinControl + "></div";
                    this.Messages = this.Messages + SkinController.FormatMessage(CONTROL_FORMAT, "&lt;" + SkinControl + "&gt;", 2, false);
                    return ("<" + SkinControl + ">");
                }
                this.Messages = this.Messages + SkinController.FormatMessage(TOKEN_NOTFOUND, "[" + m.Groups["token"].Value + "]", 2, false);
                return ("[" + m.Groups["token"].Value + "]");
            }

            private XmlDocument Attributes
            {
                get
                {
                    return this.m_Attributes;
                }
                set
                {
                    this.m_Attributes = value;
                }
            }

            private Hashtable ControlList
            {
                get
                {
                    return this.m_ControlList;
                }
            }

            private MatchEvaluator Handler
            {
                get
                {
                    return new MatchEvaluator(this.TokenMatchHandler);
                }
            }

            private string Messages
            {
                get
                {
                    return this.m_ParseMessages;
                }
                set
                {
                    this.m_ParseMessages = value;
                }
            }

            private ArrayList RegisterList
            {
                get
                {
                    return this.m_RegisterList;
                }
                set
                {
                    this.m_RegisterList = value;
                }
            }

            /// -----------------------------------------------------------------------------
            /// <summary>
            /// Registration directives generated as a result of the Parse method.
            /// </summary>
            /// <returns>ArrayList of formatted registration directives.</returns>
            /// <remarks>
            /// In addition to the updated file contents, the Parse method also
            /// creates this list of formatted registration directives which can
            /// be processed later.  They are not performed in place during the
            /// Parse method in order to preserve the formatting of the input file
            /// in case additional parsing might not anticipate the formatting of
            /// those directives.  Since they are properly formatted, it is better
            /// to exclude them from being subject to parsing.
            /// </remarks>
            /// <history>
            /// [willhsc]	3/3/2004	Created
            /// </history>
            /// -----------------------------------------------------------------------------
            public ArrayList Registrations
            {
                get
                {
                    return this.m_RegisterList;
                }
            }
        }

        /// -----------------------------------------------------------------------------
        /// Project	 : DotNetNuke
        /// Class	 : SkinFileProcessor.PathParser
        /// 
        /// -----------------------------------------------------------------------------
        /// <summary>
        /// Parsing functionality for path replacement in new skin files.
        /// </summary>
        /// <remarks>
        /// This class encapsulates the data and methods necessary to appropriately
        /// handle all the path replacement parsing needs for new skin files. Parsing
        /// supported for CSS syntax and HTML syntax (which covers ASCX files also). 
        /// </remarks>
        /// <history>
        /// [willhsc]	3/3/2004	Created
        /// </history>
        /// -----------------------------------------------------------------------------
        private class PathParser
        {
            private ArrayList m_CSSPatterns = new ArrayList();
            private ArrayList m_HTMLPatterns = new ArrayList();
            private string m_Messages = "";
            private SkinParser m_ParseOption;
            private string m_SkinPath = "";
            private string SUBST = DotNetNuke.Services.Localization.Localization.GetString("Substituting", DotNetNuke.Common.Globals.GetPortalSettings());
            private string SUBST_DETAIL = DotNetNuke.Services.Localization.Localization.GetString("Substituting.Detail", DotNetNuke.Common.Globals.GetPortalSettings());

            /// -----------------------------------------------------------------------------
            /// <summary>
            /// Process regular expression matches.
            /// </summary>
            /// <param name="m">Regular expression match for path information which requires processing.</param>
            /// <returns>Properly formatted path information.</returns>
            /// <remarks>
            /// The handler is invoked by the Regex.Replace method once for each match that
            /// it encounters.  The returned value of the handler is substituted for the
            /// original match.  So the handler properly formats the path information and
            /// returns it in favor of the improperly formatted match.
            /// </remarks>
            /// <history>
            /// [willhsc]	3/3/2004	Created
            /// </history>
            /// -----------------------------------------------------------------------------
            private string MatchHandler(Match m)
            {
                string strOldTag = m.Groups["tag"].Value + m.Groups["content"].Value + m.Groups["endtag"].Value;
                string strNewTag = strOldTag;
                switch (this.ParseOption)
                {
                    case SkinParser.Localized:
                        if (strNewTag.IndexOf(this.SkinPath) == -1)
                        {
                            strNewTag = m.Groups["tag"].Value + this.SkinPath + m.Groups["content"].Value + m.Groups["endtag"].Value;
                        }
                        break;

                    case SkinParser.Portable:
                        if (strNewTag.ToLower().IndexOf("<%= skinpath %>") == -1)
                        {
                            strNewTag = m.Groups["tag"].Value + "<%= SkinPath %>" + m.Groups["content"].Value + m.Groups["endtag"].Value;
                        }
                        if (strNewTag.IndexOf(this.SkinPath) != -1)
                        {
                            strNewTag = strNewTag.Replace(this.SkinPath, "");
                        }
                        break;
                }
                this.m_Messages = this.m_Messages + SkinController.FormatMessage(this.SUBST, string.Format(this.SUBST_DETAIL, HttpUtility.HtmlEncode(strOldTag), HttpUtility.HtmlEncode(strNewTag)), 2, false);
                return strNewTag;
            }

            /// -----------------------------------------------------------------------------
            /// <summary>
            /// Perform parsing on the specified source file.
            /// </summary>
            /// <param name="Source">Pointer to Source string to be parsed.</param>
            /// <param name="RegexList">ArrayList of properly formatted regular expression objects.</param>
            /// <param name="SkinPath">Path to use in replacement operation.</param>
            /// <remarks>
            /// This procedure iterates through the list of regular expression objects
            /// and invokes a handler for each match which uses the specified path.
            /// </remarks>
            /// <history>
            /// [willhsc]	3/3/2004	Created
            /// </history>
            /// -----------------------------------------------------------------------------
            public string Parse(ref string Source, ref ArrayList RegexList, string SkinPath, SkinParser ParseOption)
            {
                this.m_Messages = "";
                this.SkinPath = SkinPath;
                this.ParseOption = ParseOption;
                int refIntHelperL0 = RegexList.Count - 1;
                for (int i = 0; i <= refIntHelperL0; i++)
                {
                    Source = ((Regex) RegexList[i]).Replace(Source, this.Handler);
                }
                return this.m_Messages;
            }

            /// -----------------------------------------------------------------------------
            /// <summary>
            /// List of regular expressions for processing CSS syntax.
            /// </summary>
            /// <returns>ArrayList of Regex objects formatted for the Parser method.</returns>
            /// <remarks>
            /// Additional patterns can be added to this list (if necessary) if properly
            /// formatted to return <tag />, <content /> and <endtag /> groups.  For future
            /// consideration, this list could be imported from a configuration file to
            /// provide for greater flexibility.
            /// </remarks>
            /// <history>
            /// [willhsc]	3/3/2004	Created
            /// </history>
            /// -----------------------------------------------------------------------------
            public ArrayList CSSList
            {
                get
                {
                    if (this.m_CSSPatterns.Count == 0)
                    {
                        string[] arrPattern = new string[] { @"(?<tag>\surl\u0028)(?<content>[^\u0029]*)(?<endtag>\u0029.*;)" };
                        int refIntHelperL0 = arrPattern.GetLength(0) - 1;
                        for (int i = 0; i <= refIntHelperL0; i++)
                        {
                            Regex re = new Regex(arrPattern[i], RegexOptions.Multiline | RegexOptions.IgnoreCase);
                            this.m_CSSPatterns.Add(re);
                        }
                        this.m_CSSPatterns.TrimToSize();
                    }
                    return this.m_CSSPatterns;
                }
            }

            private MatchEvaluator Handler
            {
                get
                {
                    return new MatchEvaluator(this.MatchHandler);
                }
            }

            /// -----------------------------------------------------------------------------
            /// <summary>
            /// List of regular expressions for processing HTML syntax.
            /// </summary>
            /// <returns>ArrayList of Regex objects formatted for the Parser method.</returns>
            /// <remarks>
            /// Additional patterns can be added to this list (if necessary) if properly
            /// formatted to return <tag />, <content /> and <endtag /> groups.  For future
            /// consideration, this list could be imported from a configuration file to
            /// provide for greater flexibility.
            /// </remarks>
            /// <history>
            /// [willhsc]	3/3/2004	Created
            /// </history>
            /// -----------------------------------------------------------------------------
            public ArrayList HTMLList
            {
                get
                {
                    if (this.m_HTMLPatterns.Count == 0)
                    {
                        string[] arrPattern = new string[] { "(?<tag><head[^>]*?\\sprofile\\s*=\\s*\")(?!https://|http://|\\\\|[~/])(?<content>[^\"]*)(?<endtag>\"[^>]*>)", "(?<tag><object[^>]*?\\s(?:codebase|data|usemap)\\s*=\\s*\")(?!https://|http://|\\\\|[~/])(?<content>[^\"]*)(?<endtag>\"[^>]*>)", "(?<tag><img[^>]*?\\s(?:src|longdesc|usemap)\\s*=\\s*\")(?!https://|http://|\\\\|[~/])(?<content>[^\"]*)(?<endtag>\"[^>]*>)", "(?<tag><input[^>]*?\\s(?:src|usemap)\\s*=\\s*\")(?!https://|http://|\\\\|[~/])(?<content>[^\"]*)(?<endtag>\"[^>]*>)", "(?<tag><iframe[^>]*?\\s(?:src|longdesc)\\s*=\\s*\")(?!https://|http://|\\\\|[~/])(?<content>[^\"]*)(?<endtag>\"[^>]*>)", "(?<tag><(?:td|th|table|body)[^>]*?\\sbackground\\s*=\\s*\")(?!https://|http://|\\\\|[~/])(?<content>[^\"]*)(?<endtag>\"[^>]*>)", "(?<tag><(?:script|bgsound|embed|xml|frame)[^>]*?\\ssrc\\s*=\\s*\")(?!https://|http://|\\\\|[~/])(?<content>[^\"]*)(?<endtag>\"[^>]*>)", "(?<tag><(?:base|link|a|area)[^>]*?\\shref\\s*=\\s*\")(?!https://|http://|\\\\|[~/]|javascript:|mailto:)(?<content>[^\"]*)(?<endtag>\"[^>]*>)", "(?<tag><(?:blockquote|ins|del|q)[^>]*?\\scite\\s*=\\s*\")(?!https://|http://|\\\\|[~/])(?<content>[^\"]*)(?<endtag>\"[^>]*>)", "(?<tag><(?:param\\s+name\\s*=\\s*\"(?:movie|src|base)\")[^>]*?\\svalue\\s*=\\s*\")(?!https://|http://|\\\\|[~/])(?<content>[^\"]*)(?<endtag>\"[^>]*>)", "(?<tag><embed[^>]*?\\s(?:src)\\s*=\\s*\")(?!https://|http://|\\\\|[~/])(?<content>[^\"]*)(?<endtag>\"[^>]*>)" };
                        int refIntHelperL0 = arrPattern.GetLength(0) - 1;
                        for (int i = 0; i <= refIntHelperL0; i++)
                        {
                            Regex re = new Regex(arrPattern[i], RegexOptions.Multiline | RegexOptions.IgnoreCase);
                            this.m_HTMLPatterns.Add(re);
                        }
                        this.m_HTMLPatterns.TrimToSize();
                    }
                    return this.m_HTMLPatterns;
                }
            }

            private SkinParser ParseOption
            {
                get
                {
                    return this.m_ParseOption;
                }
                set
                {
                    this.m_ParseOption = value;
                }
            }

            private string SkinPath
            {
                get
                {
                    return this.m_SkinPath;
                }
                set
                {
                    this.m_SkinPath = value;
                }
            }
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// Utility class for processing of skin files.
        /// </summary>
        /// <remarks>
        /// </remarks>
        /// <history>
        /// [willhsc]	3/3/2004	Created
        /// </history>
        /// -----------------------------------------------------------------------------
        private class SkinFile
        {
            private string CONTROL_DIR;
            private string CONTROL_REG;
            private string FILE_FORMAT_DETAIL;
            private string FILE_FORMAT_ERROR;
            private string FILE_LOAD;
            private string FILE_LOAD_ERROR;
            private string FILE_WRITE;
            private readonly XmlDocument m_FileAttributes;
            private string m_FileContents;
            private readonly string m_FileExtension;
            private readonly string m_FileName;
            private string m_Messages;
            private readonly string m_SkinRoot;
            private readonly string m_SkinRootPath;
            private readonly string m_WriteFileName;

            public SkinFile(string SkinContents, XmlDocument SkinAttributes)
            {
                this.m_Messages = "";
                this.FILE_FORMAT_ERROR = DotNetNuke.Services.Localization.Localization.GetString("FileFormat.Error", DotNetNuke.Common.Globals.GetPortalSettings());
                this.FILE_FORMAT_DETAIL = DotNetNuke.Services.Localization.Localization.GetString("FileFormat.Detail", DotNetNuke.Common.Globals.GetPortalSettings());
                this.FILE_LOAD = DotNetNuke.Services.Localization.Localization.GetString("SkinFileLoad", DotNetNuke.Common.Globals.GetPortalSettings());
                this.FILE_LOAD_ERROR = DotNetNuke.Services.Localization.Localization.GetString("SkinFileLoad.Error", DotNetNuke.Common.Globals.GetPortalSettings());
                this.FILE_WRITE = DotNetNuke.Services.Localization.Localization.GetString("FileWrite", DotNetNuke.Common.Globals.GetPortalSettings());
                this.CONTROL_DIR = DotNetNuke.Services.Localization.Localization.GetString("ControlDirective", DotNetNuke.Common.Globals.GetPortalSettings());
                this.CONTROL_REG = DotNetNuke.Services.Localization.Localization.GetString("ControlRegister", DotNetNuke.Common.Globals.GetPortalSettings());
                this.m_FileAttributes = SkinAttributes;
                this.Contents = SkinContents;
            }

            /// -----------------------------------------------------------------------------
            /// <summary>
            /// SkinFile class constructor.
            /// </summary>
            /// <param name="SkinRoot"></param>
            /// <param name="FileName"></param>
            /// <param name="SkinAttributes"></param>
            /// <remarks>
            /// The constructor primes the utility class with basic file information.
            /// It also checks for the existentce of a skinfile level attribute file
            /// and read it in, if found.  
            /// </remarks>
            /// <history>
            /// [willhsc]	3/3/2004	Created
            /// </history>
            /// -----------------------------------------------------------------------------
            public SkinFile(string SkinRoot, string FileName, XmlDocument SkinAttributes)
            {
                this.m_Messages = "";
                this.FILE_FORMAT_ERROR = DotNetNuke.Services.Localization.Localization.GetString("FileFormat.Error", DotNetNuke.Common.Globals.GetPortalSettings());
                this.FILE_FORMAT_DETAIL = DotNetNuke.Services.Localization.Localization.GetString("FileFormat.Detail", DotNetNuke.Common.Globals.GetPortalSettings());
                this.FILE_LOAD = DotNetNuke.Services.Localization.Localization.GetString("SkinFileLoad", DotNetNuke.Common.Globals.GetPortalSettings());
                this.FILE_LOAD_ERROR = DotNetNuke.Services.Localization.Localization.GetString("SkinFileLoad.Error", DotNetNuke.Common.Globals.GetPortalSettings());
                this.FILE_WRITE = DotNetNuke.Services.Localization.Localization.GetString("FileWrite", DotNetNuke.Common.Globals.GetPortalSettings());
                this.CONTROL_DIR = DotNetNuke.Services.Localization.Localization.GetString("ControlDirective", DotNetNuke.Common.Globals.GetPortalSettings());
                this.CONTROL_REG = DotNetNuke.Services.Localization.Localization.GetString("ControlRegister", DotNetNuke.Common.Globals.GetPortalSettings());
                this.m_FileName = FileName;
                this.m_FileExtension = Path.GetExtension(FileName);
                this.m_SkinRoot = SkinRoot;
                this.m_FileAttributes = SkinAttributes;
                string strTemp = Strings.Replace(Strings.Replace(FileName, Path.GetFileName(FileName), "", 1, -1, CompareMethod.Binary), @"\", "/", 1, -1, CompareMethod.Binary);
                this.m_SkinRootPath = DotNetNuke.Common.Globals.ApplicationPath + Strings.Mid(strTemp, Strings.InStr(1, strTemp.ToUpper(), "/PORTALS", CompareMethod.Binary));
                this.Contents = this.Read(FileName);
                string refStringHelperL0 = this.FileExtension;
                if ((((refStringHelperL0 == ".htm") || (refStringHelperL0 == ".html")) ? 1 : 0) != 0)
                {
                    this.m_WriteFileName = FileName.Replace(Path.GetExtension(FileName), ".ascx");
                    Regex PaneCheck1 = new Regex("\\s*id\\s*=\\s*\"ContentPane\"", RegexOptions.IgnoreCase);
                    Regex PaneCheck2 = new Regex(@"\s*[ContentPane]", RegexOptions.IgnoreCase);
                    if (!PaneCheck1.IsMatch(this.Contents) & !PaneCheck2.IsMatch(this.Contents))
                    {
                        this.m_Messages = this.m_Messages + SkinController.FormatMessage(this.FILE_FORMAT_ERROR, string.Format(this.FILE_FORMAT_ERROR, FileName), 2, true);
                    }
                    if (File.Exists(FileName.Replace(this.FileExtension, ".xml")))
                    {
                        try
                        {
                            this.m_FileAttributes.Load(FileName.Replace(this.FileExtension, ".xml"));
                            this.m_Messages = this.m_Messages + SkinController.FormatMessage(this.FILE_LOAD, FileName, 2, false);
                        }
                        catch (Exception exception1)
                        {
                            
                            Exception ex = exception1;
                            this.m_FileAttributes = SkinAttributes;
                            this.m_Messages = this.m_Messages + SkinController.FormatMessage(this.FILE_LOAD_ERROR, FileName, 2, true);
                            
                        }
                    }
                }
                else
                {
                    this.m_WriteFileName = FileName;
                }
            }

            /// -----------------------------------------------------------------------------
            /// <summary>
            /// Prepend ascx control directives to file contents.
            /// </summary>
            /// <param name="Registrations">ArrayList of registration directives.</param>
            /// <remarks>
            /// This procedure formats the @Control directive and prepends it and all
            /// registration directives to the file contents.
            /// </remarks>
            /// <history>
            /// [willhsc]	3/3/2004	Created
            /// </history>
            /// -----------------------------------------------------------------------------
            public string PrependASCXDirectives(ArrayList Registrations)
            {
                IEnumerator refObjectHelperL0=null;
                string Messages = "";
                string Prefix = "";
                string refStringHelperL0 = this.SkinRoot;
                if (refStringHelperL0 == SkinInfo.RootSkin)
                {
                    Prefix = Prefix + "<%@ Control language=\"vb\" CodeBehind=\"~/admin/" + this.SkinRoot + "/skin.vb\" AutoEventWireup=\"false\" Explicit=\"True\" Inherits=\"DotNetNuke.UI.Skins.Skin\" %>\r\n";
                }
                else if (refStringHelperL0 == SkinInfo.RootContainer)
                {
                    Prefix = Prefix + "<%@ Control language=\"vb\" CodeBehind=\"~/admin/" + this.SkinRoot + "/container.vb\" AutoEventWireup=\"false\" Explicit=\"True\" Inherits=\"DotNetNuke.UI.Containers.Container\" %>\r\n";
                }
                Messages = Messages + SkinController.FormatMessage(this.CONTROL_DIR, HttpUtility.HtmlEncode(Prefix), 2, false);
                try
                {
                    refObjectHelperL0 = Registrations.GetEnumerator();
                    while (refObjectHelperL0.MoveNext())
                    {
                        string Item = Conversions.ToString(refObjectHelperL0.Current);
                        Messages = Messages + SkinController.FormatMessage(this.CONTROL_REG, HttpUtility.HtmlEncode(Item), 2, false);
                        Prefix = Prefix + Item;
                    }
                }
                finally
                {
                    if (refObjectHelperL0 is IDisposable)
                    {
                        (refObjectHelperL0 as IDisposable).Dispose();
                    }
                }
                this.Contents = Prefix + this.Contents;
                return Messages;
            }

            private string Read(string FileName)
            {
                StreamReader objStreamReader = new StreamReader(FileName);
                string strFileContents = objStreamReader.ReadToEnd();
                objStreamReader.Close();
                return strFileContents;
            }

            public void Write()
            {
                if (File.Exists(this.WriteFileName))
                {
                    File.Delete(this.WriteFileName);
                }
                this.m_Messages = this.m_Messages + SkinController.FormatMessage(this.FILE_WRITE, Path.GetFileName(this.WriteFileName), 2, false);
                StreamWriter objStreamWriter = new StreamWriter(this.WriteFileName);
                objStreamWriter.WriteLine(this.Contents);
                objStreamWriter.Flush();
                objStreamWriter.Close();
            }

            public XmlDocument Attributes
            {
                get
                {
                    return this.m_FileAttributes;
                }
            }

            public string Contents
            {
                get
                {
                    return this.m_FileContents;
                }
                set
                {
                    this.m_FileContents = value;
                }
            }

            public string FileExtension
            {
                get
                {
                    return this.m_FileExtension;
                }
            }

            public string FileName
            {
                get
                {
                    return this.m_FileName;
                }
            }

            public string Messages
            {
                get
                {
                    return this.m_Messages;
                }
            }

            public string SkinRoot
            {
                get
                {
                    return this.m_SkinRoot;
                }
            }

            public string SkinRootPath
            {
                get
                {
                    return this.m_SkinRootPath;
                }
            }

            public string WriteFileName
            {
                get
                {
                    return this.m_WriteFileName;
                }
            }
        }
    }
}

